#ifndef __WIZ_BNF_GRAMMAR_HELPER_HPP__SHANHAOBO_19800429__
#define __WIZ_BNF_GRAMMAR_HELPER_HPP__SHANHAOBO_19800429__

#include <memory> // for std::auto_ptr

#include "../../Base/Utils/WizBaseUtilsNoncopyable.hpp"
#include "../../Core/Container/WizDataTypeArray.hpp"
#include "../../DataType/SmartPtr/SharedPtr/WizDataTypeSharedPtr.hpp"

namespace Wiz
{
    namespace BNF
    {
        namespace Grammar
        {
            namespace Definition
            {
                //////////////////////////////////
                template <typename GrammarT, typename ScannerT>
                struct Type
                {
                    typedef typename GrammarT::template Definition<ScannerT> tType;
                };
            } /// end of namespace Definition

            namespace Helper
            {
                namespace Base
                {
                    template <typename GrammarT>
                    struct Type
                    {
                        virtual ::Wiz::Int::Type Undefine(GrammarT*) = 0;
                        virtual ~Type() {}
                    };
                } /// end of namespace Base

                namespace List
                {
                    //////////////////////////////////
                    template <typename GrammarT>
                    struct Type : ::Wiz::Noncopyable::Type
                    {
                        typedef GrammarT                                            tGrammar;
                        typedef ::Wiz::BNF::Grammar::Helper::Base::Type<GrammarT>   tHelper;
                        typedef ::Wiz::Array::Type<tHelper*>                        tArray;

                        Type()
                        {
                        }
                        Type(const Type&)
                        {
                        }
                        ::Wiz::Void::Type PushBack(tHelper *helper)
                        {
                            m_Helpers.PushBack(helper);
                        }

                        ::Wiz::Void::Type PopBack()
                        {
                            m_Helpers.PopBack();
                        }

                        typename tArray::tSize Size() const
                        {
                            return m_Helpers.Size();
                        }

                        typename tArray::tReverseIterator
                        RBegin()
                        {
                            return m_Helpers.RBegin();
                        }

                        typename tArray::tReverseIterator
                        REnd()
                        {
                            return m_Helpers.REnd();
                        }

                        ::Wiz::Lock::Type& Lock()
                        {
                            return m_Lock;
                        }
                    private:
                        tArray                  m_Helpers;
                        ::Wiz::Lock::Type       m_Lock;
                    };
                } /// end of namespace List
                //////////////////////////////////
            } /// end of namespace Helper

            namespace Tract
            {
                struct Type
                {
                    template<typename GrammarT>
                    static ::Wiz::BNF::Grammar::Helper::List::Type<GrammarT>& Do(GrammarT const* GrmmrPtr)
                    {
                        return GrmmrPtr->m_Helpers;
                    }
                };
            } /// end of namespace Tract

            namespace Helper
            {
                //////////////////////////////////
                template <typename GrammarT, typename DerivedT, typename ScannerT>
                struct Type : private ::Wiz::BNF::Grammar::Helper::Base::Type<GrammarT>
                {
                    typedef GrammarT                                tGrammar;
                    typedef ScannerT                                tScanner;
                    typedef DerivedT                                tDerived;
                    typedef typename ::Wiz::BNF::Grammar::Definition::Type<DerivedT, ScannerT>::tType
                                                                    tDefinition;
                    typedef Type<tGrammar, tDerived, tScanner>      tThis;
                    typedef ::Wiz::SharedPtr::Type<tThis>           tThisSharedPtr;
                    typedef ::Wiz::WeakPtr::Type<tThis>             tThisWeakPtr;

                    Type* This()
                    {
                        return this; 
                    }

                    Type(tThisWeakPtr& WkPtr) : m_DefinitionsCnt(0) , m_SharedPtr(This())
                    {
                        WkPtr = m_SharedPtr;
                    }

                    tDefinition& Define(tGrammar const* TrgtGrmmr)
                    {
                        ::Wiz::BNF::Grammar::Helper::List::Type<GrammarT> &HelperList =
                            ::Wiz::BNF::Grammar::Tract::Type::Do(TrgtGrmmr);
                        typename tGrammar::tObjectID ObjID = TrgtGrmmr->GetObjectID();

                        if (m_Definitions.Size() <= ObjID)
                        {
                            m_Definitions.Resize(ObjID * 3 / 2 + 1);
                        }
                        if (::Wiz::IsValidPtr(m_Definitions[ObjID]))
                        {
                            return *m_Definitions[ObjID];
                        }

                        ::Wiz::AutoPtr::Type<tDefinition> Rslt(new tDefinition(TrgtGrmmr->Derived()));

                        ::Wiz::ScopedLock::Type lock(HelperList.Lock());
                        HelperList.PushBack(this);

                        ++m_DefinitionsCnt;
                        m_Definitions[ObjID] = Rslt.GetRawPtr();

                        return *(Rslt.Release());
                    }

                    ::Wiz::Int::Type Undefine(tGrammar* TrgtGrmmr)
                    {
                        typename tGrammar::tObjectID ObjID = TrgtGrmmr->GetObjectID();

                        if (m_Definitions.Size() <= ObjID)
                        {
                            return 0;
                        }

                        delete m_Definitions[ObjID];
                        m_Definitions[ObjID] = WIZ_NULLPTR;
                        
                        if (--m_DefinitionsCnt == 0)
                        {
                            m_SharedPtr.Reset();
                        }
                        
                        return 0;
                    }
                private:
                    ::Wiz::Array::Type<tDefinition*>    m_Definitions;
                    ::Wiz::UInt::Type                   m_DefinitionsCnt;
                    tThisSharedPtr                      m_SharedPtr;
                };
            } /// end of namespace Helper
        } /// end of namespace Grammar
    } /// end of namespace BNF
} /// end of namespace Wiz

#endif /*__WIZ_BNF_GRAMMAR_HELPER_HPP__SHANHAOBO_19800429__*/
